
#### HOW TO RUN ME?
#### export PYTHONPATH=$PYTHONPATH:/home/swara/VCDutils/Verilog_VCD-1.05/install/lib/python2.7/site-packages/Verilog_VCD
#### python cvd_read.py

import logging, pickle, os, optparse
logging.basicConfig(level=logging.INFO, format='%(asctime)s||| %(message)s')


def range_intersection(r1, r2) :
	assert r1[0] <= r1[1] and r2[0] <= r2[1]
	if   r2[0] <= r1[0] and r1[0] <= r2[1] :
		if   r2[0] <= r1[1] and r1[1] <= r2[1] :
			return [r1[0],r1[1]] #r1[1]-r1[0]
		else :
			return [r1[0],r2[1]] #r2[1]-r1[0]
	elif r1[0] <= r2[0] and r2[0] <= r1[1] :
		if   r1[0] <= r2[1] and r2[1] <= r1[1] :
			return [r2[0],r2[1]] #r2[1]-r2[0]
		else :
			return [r2[0],r1[1]] #r1[1]-r2[0]
	else :
		return [-1,-1]

def get_vcd_object(fn) :
	from Verilog_VCD import parse_vcd
	return parse_vcd(fn)
	pklfile = fn+'.pkl'
	if os.path.isfile(pklfile) :
		return pickle.load( open(pklfile,'rb') )
	else :
		from Verilog_VCD import parse_vcd
		vcd = parse_vcd(fn)
		ofp = open(pklfile, 'wb')
		pickle.dump(vcd, ofp)
		ofp.close()
		return get_vcd_object(fn)


def signal_name_to_key(vcd, name) :
	for k in vcd.keys() :
		if name == vcd[k]['nets'][0]['name'] : return k
	assert 1==0, 'No signal key found for ' + name

def find_signal_state_time_intervals(MAX_SIMU_TIME, vcd, signame, state) :
	sigkey = signal_name_to_key(vcd, signame)
	uniq_vals = set()
	tv = vcd[sigkey]['tv']
	for t,v in tv :
		uniq_vals.add(v)
	#logging.info('Unique values of ' + signame + ' are ' + str(uniq_vals))
	current_period = [None,None]
	periods = []
	for t,v in tv :
		logging.debug(str([t,v]))
		if v == state :
			assert current_period[0] == None
			current_period[0] = t
		else :
			assert current_period[1] == None
			current_period[1] = t
			if current_period[0] == None :
				assert current_period[1] == 0
				current_period[0] = 0
			periods.append(current_period)
			current_period = [None,None]
	if current_period[0] != None and current_period[1] == None :
		current_period[1] = MAX_SIMU_TIME
		periods.append(current_period)
	logging.debug('%s = %s for periods %s' % (signame, state, str(periods)))
	return periods

def common_time(MAX_SIMU_TIME, vcd, sig1, st1, sig2, st2) :
	periods1 = find_signal_state_time_intervals(MAX_SIMU_TIME, vcd,sig1,st1)
	periods2 = find_signal_state_time_intervals(MAX_SIMU_TIME, vcd,sig2,st2)
	common_period = 0
	for p1 in periods1 :
		for p2 in periods2 :
			shared_range = range_intersection(p1, p2)
			common_period += shared_range[1] - shared_range[0]
	assert common_period <= MAX_SIMU_TIME
        percent_stall = (100.*common_period)/MAX_SIMU_TIME
	logging.info('Shared time %s:::%s %s:::%s = %d (%.2f%%)' % (sig1,st1,sig2,st2,common_period,percent_stall))
        return percent_stall 


prefixes, suffixes = ['A','B'], ['0','1']
def iter_sig_ready() :
	for prefix in prefixes :
		for suffix in suffixes :
			for midfix in ['AR','R','B','AW','W'] :
				yield prefix+'_uMCTL2Wrapper.'+midfix+'Ready_'+suffix, '0', prefix+'_uMCTL2Wrapper.'+midfix+'Valid_'+suffix, '1'
def iter_sig_valid() :
	for prefix in prefixes :
		for suffix in suffixes :
			yield prefix+'_uMCTL2Wrapper.ARValid_'+suffix, '1'

def parse_vcd(VCD_FILENAME):
	MAX_SIMU_TIME = -1e10
        logging.info('Reading ' + VCD_FILENAME)
        myvcd = get_vcd_object(VCD_FILENAME)
        logging.info('Done reading ' + VCD_FILENAME)
        for k in myvcd.keys() :
                tvs = myvcd[k]['tv']
                # logging.info( str([k, vcd[k]['nets'][0]['name'], len(tvs)]) )
                mt = tvs[ len(tvs)-1 ][0]
                if MAX_SIMU_TIME < mt : MAX_SIMU_TIME = mt
                #logging.info('Last simulation time stamp ' + str(MAX_SIMU_TIME)) 
        stalls = {}
        for s1,t1,s2,t2 in iter_sig_ready() :
                percent_stall = common_time(MAX_SIMU_TIME, myvcd, s1, t1, s2, t2)
                ddr_ch = s1[0]
                ddr_port = s1[len(s1)-1]
                axi_ch = s1[s1.index('.')+1:s1.index('.')+3]
                if not stalls.has_key(ddr_ch) : stalls[ddr_ch] = {}
                if not stalls[ddr_ch].has_key(ddr_port) : stalls[ddr_ch][ddr_port] = {}
                stalls[ddr_ch] [ddr_port] [axi_ch] = percent_stall
        return stalls

if __name__ == '__main__':
        
        VCD_FILENAME = 'europa_noc_spec_signals.vcd'
        parser = optparse.OptionParser()
        #parser.add_option('--vcdfile', default='DYNAMIC_rdonly_uMCTL2Signals.vcd', help='VCD input file to analyze, default to '+VCD_FILENAME)
        #parser.add_option('--vcdfile', default='HSUM_rdonly_uMCTL2Signals.vcd', help='VCD input file to analyze, default to '+VCD_FILENAME)
        #parser.add_option('--vcdfile', default='RDWR_uMCTL2Signals.vcd', help='VCD input file to analyze, default to '+VCD_FILENAME)
        parser.add_option('--vcdfile', default='europa_noc_spec_signals.vcd', help='VCD input file to analyze, default to '+VCD_FILENAME)
        (opts, args) = parser.parse_args()
        VCD_FILENAME = opts.vcdfile
        parse_vcd(VCD_FILENAME)
